﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Spinning.Spinning.Unitity;
using Microsoft.Xna.Framework;
using Microsoft.Devices.Sensors;
using System.Net;
using Spinning.Spinning.Entity.Battle;
using Box2D.XNA;
using Spinning.Spinning.UI;
using Spinning.Spinning.Unitity.EntityModifiers;

namespace Spinning.Spinning.Entity.Scenes
{
    class ClientScene : BaseScene
    {
        Vector3 _accelReading = new Vector3();
        //Player Enemy;
        FakeBattlePlayer PlayerSprite, EnemySprite;
        protected StatusBar bar;
        EnemyBar bossBar;
        private UdpAnySourceMulticastChannel Channel { get; set; }
        TextEntity te;
        String _packetInfo = "";

        public ClientScene()
            : base()
        {
            Game1._acceleMeter.CurrentValueChanged += GSensorChanged;
            try
            {
                Game1._acceleMeter.Start();
            }
            catch (AccelerometerFailedException e) { throw e; }
            catch (UnauthorizedAccessException e) { throw e; }
        }

        void GSensorChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
        {
            _accelReading.X = (float)e.SensorReading.Acceleration.X;
            _accelReading.Y = -(float)e.SensorReading.Acceleration.Y;
            _accelReading.Z = (float)e.SensorReading.Acceleration.Z;    
        }

        public override void OnLoad()
        {
            base.OnLoad();

            Sprite backGroundSprite = new Sprite();
            backGroundSprite.textureName = "bg";
            backGroundSprite.ZIndex = Constants.background;
            backGroundSprite.OnLoad();
            this.Attach(backGroundSprite);

            int fullLife = Game1.stageManager.LifeTimeEarnByUser * 5;
            int enemyFullLife = Game1.stageManager.BattleData.EnemyLifeTimeEarn * 5;

            if (Game1.stageManager.GameSrate.CurrentPlayer == Constants.PlayerId.Omega) fullLife += 25;
            if (Game1.stageManager.BattleData.CurrentEnemy == Constants.PlayerId.Omega) enemyFullLife += 25;

            PlayerSprite = new FakeBattlePlayer();
            PlayerSprite.textureName = "spinning";
            PlayerSprite.OnLoad();
            PlayerSprite.Origin = new Vector2(0.5f);
            PlayerSprite.SetAnimation(Constants.playerAnimationFrame);
            //PlayerSprite.SetChangeFrameAnimation(new int[] { 2, 3 });
            PlayerSprite.ZIndex = Constants.player;
            this.Attach(PlayerSprite);

            bar = new StatusBar();
            bar.OnLoad();
            bar.Position = new Vector2(10, 10);
            Attach(bar);
            bar.SpeedBar.Full = fullLife;
            bar.SpeedBar.Value = fullLife;

            switch (Game1.stageManager.GameSrate.CurrentPlayer)
            {
                case Constants.PlayerId.Phi:
                    bar.Property = Constants.Property.Fire;
                    break;
                case Constants.PlayerId.Theta:
                    bar.Property = Constants.Property.Water;
                    break;
                case Constants.PlayerId.Omega:
                    bar.Property = Constants.Property.Wind;
                    break;
            }
            switch (Game1.stageManager.GameSrate.PlayerSpinningType)
            {
                case Constants.SpinningType.Phi:
                    PlayerSprite.Style = 0;
                    break;
                case Constants.SpinningType.Theta:
                    PlayerSprite.Style = 2;
                    break;
                case Constants.SpinningType.Omega:
                    PlayerSprite.Style = 3;
                    break;
                case Constants.SpinningType.India:
                    PlayerSprite.Style = 4;
                    break;
                case Constants.SpinningType.Russia:
                    PlayerSprite.Style = 5;
                    break;
                case Constants.SpinningType.Tiawan:
                    PlayerSprite.Style = 6;
                    break;
            }

            EnemySprite = new FakeBattlePlayer();
            EnemySprite.textureName = "spinning";
            EnemySprite.OnLoad();
            EnemySprite.Origin = new Vector2(0.5f);
            EnemySprite.SetAnimation(Constants.playerAnimationFrame);
            EnemySprite.SetChangeFrameAnimation(new int[] { 2, 3 });
            EnemySprite.ZIndex = Constants.enemy;
            this.Attach(EnemySprite);

            bossBar = new EnemyBar();
            bossBar.OnLoad();
            bossBar.SpeedBar.Full = enemyFullLife;
            bossBar.SpeedBar.Value = enemyFullLife;
            bossBar.Position = new Vector2(-70, -90);
            EnemySprite.Attach(bossBar);

            switch (Game1.stageManager.BattleData.CurrentEnemy)
            {
                case Constants.PlayerId.Phi:
                    bossBar.Player = Constants.PlayerId.Phi;
                    break;
                case Constants.PlayerId.Theta:
                    bossBar.Player = Constants.PlayerId.Theta;
                    break;
                case Constants.PlayerId.Omega:
                    bossBar.Player = Constants.PlayerId.Omega;
                    break;
            }

            switch (Game1.stageManager.BattleData.EnemySpinningType)
            {
                case Constants.SpinningType.Phi:
                    EnemySprite.Style = 0;
                    break;
                case Constants.SpinningType.Theta:
                    EnemySprite.Style = 2;
                    break;
                case Constants.SpinningType.Omega:
                    EnemySprite.Style = 3;
                    break;
                case Constants.SpinningType.India:
                    EnemySprite.Style = 4;
                    break;
                case Constants.SpinningType.Russia:
                    EnemySprite.Style = 5;
                    break;
                case Constants.SpinningType.Tiawan:
                    EnemySprite.Style = 6;
                    break;
            }

            FakeStageItemListBar fsilb = new FakeStageItemListBar();
            fsilb.OnLoad();
            fsilb.Position = new Vector2(100);
            this.Attach(fsilb);
            fsilb.OnUseItemMessageEvent += OnUseItemMessage;

            //StageItemListBar silb = new StageItemListBar(Player, Enemy);
            //silb.OnLoad();
            //silb.Position = new Vector2(100);
            //this.Attach(silb);

            te = new TextEntity();
            ResourceManager.ContentRoot = "";
            te.fontString = "TestFont";
            te.OnLoad();
            te.Origin = new Vector2(0.5f);
            te.Position = new Vector2(200, 200);
            te.Color = Color.Blue;
            te.Alpha = 0;
            te.ZIndex = Constants.debugText;
            Attach(te);
            te.Value = "client";

            _packetInfo = "hostId:" + Game1.hostId + ",clientId:" + Game1.clientId + ",isHost:" + Game1.stageManager.IsHost + ",";

            this.Channel = new UdpAnySourceMulticastChannel(IPAddress.Parse("224.0.1.100"), 3000);
            this.Channel.AfterOpen += new EventHandler(Channel_AfterOpen);
            this.Channel.BeforeClose += new EventHandler(Channel_BeforeClose);
            this.Channel.PacketReceived += new EventHandler<UdpPacketReceivedEventArgs>(Channel_PacketReceived);

            this.Channel.Open();
        }

        void OnUseItemMessage(string s) 
        {
            this.Channel.Send(_packetInfo + "enemyUseItemMessage:{0},", s);
        }

        void Channel_BeforeClose(object sender, EventArgs e)
        {
            this.Channel.Send("END,{0}, leaves the UDP Multicast chat,", Game1.clientId);
        }

        void Channel_AfterOpen(object sender, EventArgs e)
        {
            this.Channel.Send("BEGIN,{0}, enters the UDP Multicast chat,", Game1.clientId);
        }

        //沒用到Channel.close(); 範例也沒

        void Channel_PacketReceived(object sender, UdpPacketReceivedEventArgs e)
        {
            string[] temp;
            string[] temp1;

            temp = e.Message.Split(',');

            NoKeyFoundDictionary dataDictionary = new NoKeyFoundDictionary();

            bool partyFlag = false;

            for (int i = 0; i < temp.Length; i++)
            {
                temp1 = temp[i].Split(':');
                if (temp1.Length >= 2)
                    dataDictionary.Add(temp1[0], temp1[1]);
            }

            if (dataDictionary.Get("hostId") == Game1.hostId && dataDictionary.Get("clientId") == Game1.clientId && dataDictionary.Get("isHost") == "True") //host 來的封包
            {
                partyFlag = true;
            }
            else
            {
                partyFlag = false;
            }

            if (partyFlag)
            {
                if (dataDictionary.Get("updateMode") == "True")
                {
                    PlayerSprite.Position = new Vector2(float.Parse(dataDictionary.Get("enemyPosX")), float.Parse(dataDictionary.Get("enemyPosY")));
                    EnemySprite.Position = new Vector2(float.Parse(dataDictionary.Get("playerPosX")), float.Parse(dataDictionary.Get("playerPosY")));
                    UpdateSpinningType(dataDictionary);
                    bar.SpeedBar.Value = Convert.ToInt32(dataDictionary.Get("enemyLife"));
                    bossBar.SpeedBar.Value = Convert.ToInt32(dataDictionary.Get("playerLife"));
                }

                if (dataDictionary.Get("playerAttackMessage") != "noKey") 
                {
                    EnemySprite.AttackMessage(dataDictionary.Get("playerAttackMessage"));
                }

                if (dataDictionary.Get("enemyAttackMessage") != "noKey")
                {
                    PlayerSprite.AttackMessage(dataDictionary.Get("enemyAttackMessage"));
                }

                if (dataDictionary.Get("isLose") != "noKey")
                {
                    RotationModifier rm = new RotationModifier(0, 3, 0, (float)Math.PI / 2);
                    if (dataDictionary.Get("isLose") == "True")
                    {
                        PlayerSprite.AddModifier(rm);
                        PlayerSprite.IsReplay = false;
                    }
                    else 
                    {
                        EnemySprite.AddModifier(rm);
                        EnemySprite.IsReplay = false;
                    }
                }

                if (dataDictionary.Get("isWin") != "noKey")
                {
                    Game1.stageManager.stageScoreData.isWin = dataDictionary.Get("isWin")=="True";
                    Game1.stageManager.stageScoreData.isBossStage = false;
                    Game1.stageManager.stageScoreData.isBattle = true;
                    Game1.stageManager.stageScoreData.Speed = Convert.ToInt32(dataDictionary.Get("Speed"));
                    Game1.stageManager.stageScoreData.Time = Convert.ToInt32(dataDictionary.Get("Time"));
                    Game1.stageManager.stageScoreData.Bouns = Convert.ToInt32(dataDictionary.Get("Bouns"));
                    OnEndCondition();
                }
                
                tempCounter++;
                te.Value = "ClientCounter:" + tempCounter;
            
            }
        }

        private void UpdateSpinningType(NoKeyFoundDictionary dataDictionary)
        {
            switch (dataDictionary.Get("enemyMoveType"))
            {
                case "Forward":
                    PlayerSprite.CurrentSpinningType = FakeBattlePlayer.SpinningMoveType.Forward;
                    break;
                case "StayMeddle":
                    PlayerSprite.CurrentSpinningType = FakeBattlePlayer.SpinningMoveType.StayMeddle;
                    break;
                case "GoBack":
                    PlayerSprite.CurrentSpinningType = FakeBattlePlayer.SpinningMoveType.GoBack;
                    break;
            }

            switch (dataDictionary.Get("playerMoveType"))
            {
                case "Forward":
                    EnemySprite.CurrentSpinningType = FakeBattlePlayer.SpinningMoveType.Forward;
                    break;
                case "StayMeddle":
                    EnemySprite.CurrentSpinningType = FakeBattlePlayer.SpinningMoveType.StayMeddle;
                    break;
                case "GoBack":
                    EnemySprite.CurrentSpinningType = FakeBattlePlayer.SpinningMoveType.GoBack;
                    break;
            }
        }

        int tempTimer = 0;
        Vector3 preAcc;
        int tempCounter;
        protected override void UpdateSelf(GameTime gameTime)
        {
            base.UpdateSelf(gameTime);
            int delta = gameTime.ElapsedGameTime.Milliseconds;
            tempTimer += delta;
            if (tempTimer / 50 >= 1)
            {
            //    tempTimer = tempTimer % 50;

            if (checkDif(_accelReading,preAcc,0.05f))
                this.Channel.Send("hostId:{0},clientId:{1},accX:{2},accY:{3},accZ:{4},isHost:False,updateMode:True,", Game1.hostId, Game1.clientId, _accelReading.X, _accelReading.Y, _accelReading.Z);
                preAcc = _accelReading;
            
            //    //this.Channel.Send("{0},{1},{2},{3},", Game1.hostId, _accelReading.X, _accelReading.Y, _accelReading.Z);
            }
            
        }

        bool checkDif(Vector3 a, Vector3 b, float diff) 
        {
            if (Math.Abs(a.X - b.X) > diff || Math.Abs(a.Y - b.Y) > diff)
                return true;
            else
                return false;
        }

        public void OnEndCondition()
        {
            Game1.stageManager.GoToScene("reward");
        }

        public override BaseScene Clone()
        {
            BaseScene scene = new ClientScene();
            scene.Size = new Vector2(Constants.Window_Width, Constants.Window_Height);
            scene.OnLoad();
            scene.SortChildren();
            return scene;
        }
    }
}

